﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using ProgramMain.Layers;

namespace ProgramMain.NetVis
{
    public class SectionConnectionRange : RangeBase
    {
        public enum Position { Entity, Vertical, Horizontal }
        public SectionConnectionRange() { }

        public SectionConnectionRange(Layers.VisLayer vis): base(vis)
        {
            Hint = "";
        }

        private const int h = 8;

        [XmlIgnore]
        public LineConnectionRange Ovner { get; set; }

        private Point _virtualPoint1;
        private Point _virtualPoint2;

        public Point VirtualPoint1
        {
            get { return _virtualPoint1; }
            set
            {
                if (_virtualPoint1 == value) return;
                Point old = _virtualPoint1;
                _virtualPoint1 = value;
                if (Vis != null) _calcPointTwo(old, value);
            }
        }

        public Point VirtualPoint2
        {
            get { return _virtualPoint2; }
            set
            {
                if (_virtualPoint2 == value) return;
                Point old = _virtualPoint2;
                _virtualPoint2 = value;
                if (Vis != null) _calcPointTwo(old, value);
            }
        }

        [XmlIgnore]
        public int StaticPoint { get; private set; }

        public event EventHandler<ShiftConnection> ShiftConnectionEvent;
        public event EventHandler<ShiftConnection> CreateSectionEvent;
        public event EventHandler<ShiftConnection> DeleteSectionEvent;

        public void DeleteSection()
        {
            if (DeleteSectionEvent != null)
                DeleteSectionEvent(this, new ShiftConnection(VirtualPoint1, VirtualPoint2));
        }

        public Size GetVectorByPoint(Point point)
        {
            if (VirtualPoint1 == point) return new Size(VirtualPoint2.X - VirtualPoint1.X, VirtualPoint2.Y - VirtualPoint1.Y);
            if (VirtualPoint2 == point) return new Size(VirtualPoint1.X - VirtualPoint2.X, VirtualPoint1.Y - VirtualPoint2.Y);
            return Size.Empty;
        }

        public int Lenght()
        {
            Size size = new Size(VirtualPoint1.X - VirtualPoint2.X, VirtualPoint1.Y - VirtualPoint2.Y);
            return (int)Math.Round(Math.Pow((size.Width * size.Width + size.Height * size.Height), 0.5), 0);
        }

        private void _calcPointTwo(Point pointOld, Point pointNew)
        {
            Size tmp = Size.Empty;
            Point tmpPoint = Point.Empty;
            switch (PositionState)
            {
                case Position.Vertical: tmp = new Size(pointNew.X - pointOld.X, 0);
                    break;
                case Position.Horizontal: tmp = new Size(0, pointNew.Y - pointOld.Y);
                    break;
                case Position.Entity: tmp = new Size(pointNew.X - pointOld.X, pointNew.Y - pointOld.Y);
                    break;
                default:
                    tmp = Size.Empty;
                    break;
            }
            if (_virtualPoint1 == pointNew)
            {
                if (StaticPoint == 2 &&
                    ((PositionState == Position.Vertical && tmp.Width != 0) || (PositionState == Position.Horizontal && tmp.Height != 0))
                    )
                {
                    Point p = new Point((pointOld.X + _virtualPoint2.X) / 2, (pointOld.Y + _virtualPoint2.Y) / 2);
                    CreateNewSection(p, tmp);
                }
                else
                {
                    tmpPoint = _virtualPoint2;
                    _virtualPoint2 += tmp;
                    if (ShiftConnectionEvent != null)
                        ShiftConnectionEvent(this, new ShiftConnection(tmpPoint, _virtualPoint2));
                }
            }

            if (_virtualPoint2 == pointNew)
            {
                if (StaticPoint == 1 &&
                    ((PositionState == Position.Vertical && tmp.Width != 0) || (PositionState == Position.Horizontal && tmp.Height != 0))
                    )
                {
                    Point p = new Point((pointOld.X + _virtualPoint1.X) / 2, (pointOld.Y + _virtualPoint1.Y) / 2);
                    CreateNewSection(p, tmp);
                }
                else
                {
                    tmpPoint = _virtualPoint1;
                    _virtualPoint1 += tmp;
                    if (ShiftConnectionEvent != null)
                        ShiftConnectionEvent(this, new ShiftConnection(tmpPoint, _virtualPoint1));
                }
            }
        }

        private bool _isActive = false;

        [XmlIgnore]
        public bool IsActive
        {
            get { return _isActive; }
            set
            {
                if (_isActive != value)
                {
                    _isActive = value;
                    _linePen = value ? _linePen = new Pen(Color.Red, 2) : new Pen(Color.Green, 1);
                }
            }
        }

        private Pen _linePen = new Pen(Color.Green, 1);

        [XmlIgnore]
        public Point Point1
        {
            get { return Vis.GetLocation(VirtualPoint1); }
        }
     
        [XmlIgnore]
        public Point Point2
        {
            get { return Vis.GetLocation(VirtualPoint2); }
        }

        public void SetPoints(Point point1, Point point2, int staticPoint)
        {
            _virtualPoint1 = point1;
            _virtualPoint2 = point2;
            StaticPoint = staticPoint;


            if (Point1.X == Point2.X) PositionState = Position.Vertical;
            else if (Point1.Y == Point2.Y) PositionState = Position.Horizontal;
            else PositionState = Position.Entity;
        }
        
        [XmlIgnore]
        public Position PositionState { get; private set; }

        public override bool Shift(Size distance)
        {
            if (StaticPoint != 0) return false;
            Point tmpPoint1 = VirtualPoint1;
            switch (PositionState)
            {
                case Position.Vertical:
                    VirtualPoint1 = _virtualPoint1 + new Size(distance.Width, 0);
                    break;
                case Position.Horizontal:
                    VirtualPoint1 = _virtualPoint1 + new Size(0, distance.Height);
                    break;
                case Position.Entity:
                    VirtualPoint1 = _virtualPoint1 + distance;
                    break;
            }
            if (ShiftConnectionEvent != null && tmpPoint1 != VirtualPoint1)
                ShiftConnectionEvent(this, new ShiftConnection(tmpPoint1, _virtualPoint1));
            return true;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj is SectionConnectionRange)
            {
                SectionConnectionRange s = (SectionConnectionRange)obj;
                //  if (VirtualPoint1 == s.VirtualPoint1 && VirtualPoint2 == s.VirtualPoint2) return true;
                if (PositionState == s.PositionState) return true;
            }
            return false;

        }

        [XmlIgnore]
        public override Point Location
        {
            get
            {
                if (Point1.X == Point2.X)
                {
                    Point p = Point1 + new Size((-1) * h / 2, 0);
                    return p;
                }

                if (Point1.Y == Point2.Y)
                {
                    Point p = Point1 + new Size(0, (-1) * h / 2);
                    return p;
                }
                return Point1;
            }
        }

        public override Size LocationSize
        {
            get
            {
                if (Point1.X == Point2.X) return new Size(h, Point2.Y - Point1.Y);
                if (VirtualPoint1.Y == VirtualPoint2.Y) return new Size(Point2.X - Point1.X, h);
                return new Size(Point2.X - Point1.X, Point2.Y - Point1.Y);
            }
        }

        public override void Draw(Graphics layer)
        {
            layer.DrawLine(_linePen, Point1, Point2);
        }

        public void CreateNewSection(Point point, Size size)
        {
            Point calcPoint = Point.Empty;
            switch (PositionState)
            {
                case Position.Horizontal:
                    point.Y = StaticPoint == 2 ? VirtualPoint2.Y : VirtualPoint1.Y;
                    if (size == Size.Empty) size = new Size(0, h);
                    calcPoint = point + size;
                    break;
                case Position.Vertical:
                    point.X = StaticPoint == 2 ? VirtualPoint2.X : VirtualPoint1.X;
                    if (size == Size.Empty) size = new Size(h, 0);
                    calcPoint = point + size;
                    break;
            }
            if (calcPoint != Point.Empty && point != Point.Empty && CreateSectionEvent != null)
            {
                CreateSectionEvent(this, new ShiftConnection(point, calcPoint));
            }
        }

        public override bool RemoveRectange()
        {
            if (Ovner != null) Ovner.RemoveSection(this);
            return base.RemoveRectange();
        }
    }
}